#pragma once

#include <pcap.h>
#include <atomic>
#include <cstdint>
#include <string>
#include <thread>
#include <mutex>

#include "core/IDevice.h"

// Forward declaration.
class DeviceManager;

class PcapDevice : public IDevice {
 public:
    ~PcapDevice() override;

    /// Delete copy and assignment constructor.
    PcapDevice(const PcapDevice&) = delete;
    PcapDevice& operator=(const PcapDevice&) = delete;

    /// Delete move constructor.
    PcapDevice(PcapDevice&&) = delete;
    PcapDevice& operator=(PcapDevice&&) = delete;

    /// IDevice interface implementation
    bool open(const std::string& deviceName) override;
    void close() override;
    bool isOpen() const override;

    bool startCapture() override;
    void stopCapture() override;
    bool injectPacket(const uint8_t* data, size_t length) override;
    bool injectPacket(const Packet& packet) override;

    bool setBPFFilter(const std::string& filterExpression) override;
    /// @brief Only activated device can set BPF filter.
    bool applyBPFFilter();

    bool setDispatcher(std::shared_ptr<PacketDispatcher> dispatcher) override {
        m_dispatcher = dispatcher;
        return true;
    }
    std::shared_ptr<PacketDispatcher> getDispatcher() override { return m_dispatcher; }

    bool setPromiscuousMode(bool enabled) override;
    bool setTimeout(int milliseconds) override;
    bool setBufferSize(int size) override;
    bool setSnapshotLength(int snapshot_len) override;
    bool setFilter(const std::string& filterExpression) override;
    void setPacketCallback(PacketCallBack callback) override;

    uint64_t getPacketReceived() const override;
    uint64_t getPacketDropped() const override;
    uint64_t getBytesReceived() const override;

    std::string getName() const override;
    std::string getDescription() const override;

    /// pcap functions
    bool activate();

    /// Higher functions, new version of libpcap support.
    bool setImmediateMode(bool enabled);
    /// @brief Wireless monitor mode, only Wireless network card supports.
    bool setRFMonitorMode(bool enabled);

    void captureLoop();
    bool cleanup();
    bool destroy();

 private:
    /// @brief Private constructor function, only friend class DeviceManager can create instance.
    PcapDevice();

    // declare a friend class
    friend class DeviceManager;

    pcap_t* m_handle;
    std::string m_deviceName;
    std::string m_error;
    bool m_isActivated;
    std::string m_currentFilter;
    std::string m_BPFFilter;
    std::shared_ptr<PacketDispatcher> m_dispatcher;

    std::atomic<uint64_t> m_packetsReceived;
    std::atomic<uint64_t> m_packetsDropped;
    std::atomic<uint64_t> m_bytesReceived;
    std::atomic<bool> m_isCapturing{false};

    std::thread m_captureThread;
    mutable std::mutex m_captureMutex;      /// protect capture status and resources
    PacketCallBack m_callback;

    static void packetHandler(u_char* userData, const struct pcap_pkthdr* header, const u_char* packetData);
};